package app

import (
	"fmt"
	"github.com/pion/rtcp"
	"github.com/pion/webrtc"
	"io"
	"signal"
	"time"
)

type Connection struct {
	Conn *webrtc.PeerConnection
	track *webrtc.Track
}

var (
	m webrtc.MediaEngine
	api *webrtc.API
)

func NewConnection() *Connection {
	conn := &Connection{};
	peerConnectionConfig := webrtc.Configuration{
		ICEServers: []webrtc.ICEServer{
			{
				URLs: []string{"stun:stun.l.google.com:19302"},
			},
		},
	}
	// Create a new RTCPeerConnection
	conn.Conn, _ = api.NewPeerConnection(peerConnectionConfig)

	// Allow us to receive 1 video track
	if _, err := conn.Conn.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil {
		panic(err)
	}
	return conn;
}

func InitWebRtc() {
	// Everything below is the Pion WebRTC API, thanks for using it ❤️.
	// Create a MediaEngine object to configure the supported codec
	m = webrtc.MediaEngine{}

	// Setup the codecs you want to use.
	// Only support VP8, this makes our proxying code simpler
	m.RegisterCodec(webrtc.NewRTPVP8Codec(webrtc.DefaultPayloadTypeVP8, 90000))
	m.RegisterCodec(webrtc.NewRTPVP8Codec(webrtc.DefaultPayloadTypeH264, 90000))

	// Create the API object with the MediaEngine
	api = webrtc.NewAPI(webrtc.WithMediaEngine(m))
}

func (conn *Connection) PushPeer(sdp string) string {

	offer := webrtc.SessionDescription{}
	signal.Decode(sdp, &offer)

	// Set the remote SessionDescription
	err := conn.Conn.SetRemoteDescription(offer)
	if err != nil {
		panic(err)
	}

	// Create answer
	answer, err := conn.Conn.CreateAnswer(nil)
	if err != nil {
		panic(err)
	}

	// Sets the LocalDescription, and starts our UDP listeners
	err = conn.Conn.SetLocalDescription(answer)
	if err != nil {
		panic(err)
	}

	// Set a handler for when a new remote track starts, this just distributes all our packets
	// to connected peers
	conn.Conn.OnTrack(func(remoteTrack *webrtc.Track, receiver *webrtc.RTPReceiver) {
		var newTrackErr error;
		// Send a PLI on an interval so that the publisher is pushing a keyframe every rtcpPLIInterval
		// This can be less wasteful by processing incoming RTCP events, then we would emit a NACK/PLI when a viewer requests it
		go func() {
			ticker := time.NewTicker(rtcpPLIInterval)
			for range ticker.C {
				if rtcpSendErr := conn.Conn.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: remoteTrack.SSRC()}}); rtcpSendErr != nil {
					fmt.Println(rtcpSendErr)
				}
			}
		}()

		// Create a local track, all our SFU clients will be fed via this track
		conn.track, newTrackErr = conn.Conn.NewTrack(remoteTrack.PayloadType(), remoteTrack.SSRC(), "video", "pion")
		if newTrackErr != nil {
			panic(newTrackErr)
		}

		rtpBuf := make([]byte, 1400)
		for {
			i, readErr := remoteTrack.Read(rtpBuf)
			if readErr != nil {
				panic(readErr)
			}

			// ErrClosedPipe means we don't have any subscribers, this is ok if no peers have connected yet
			if _, err := conn.track.Write(rtpBuf[:i]); err != nil && err != io.ErrClosedPipe {
				panic(err)
			}
		}
	})

	return signal.Encode(answer);
}


func (conn *Connection) PullPeer(other *Connection,sdp string) {


	recvOnlyOffer := webrtc.SessionDescription{}
	signal.Decode(sdp, &recvOnlyOffer)

	_, err := conn.Conn.AddTrack(other.track)
	if err != nil {
		panic(err)
	}

	// Set the remote SessionDescription
	err  = conn.Conn.SetRemoteDescription(recvOnlyOffer)
	if err != nil {
		panic(err)
	}

	// Create answer
	answer, err := conn.Conn.CreateAnswer(nil)
	if err != nil {
		panic(err)
	}

	// Sets the LocalDescription, and starts our UDP listeners
	err = conn.Conn.SetLocalDescription(answer)
	if err != nil {
		panic(err)
	}
}